from datetime import datetime, timedelta, timezone

from core.aai.jwt_backends import TokenBackend, JWTInvalidError, BaseAAIToken
from apps.app_auth_provider.managers import auth_provider_configs
from apps.app_auth_provider.models import InternalUser


def aware_utcnow() -> datetime:
    return datetime.now(tz=timezone.utc)


def build_token_backend():
    verifying_key = auth_provider_configs.get(auth_provider_configs.ConfigName.JWT_PUBLIC_KEY.value)
    if not verifying_key and not verifying_key.strip(' '):
        raise JWTInvalidError(
            'The public key of JWT is not configured in the configuration of the admin site')

    signing_key = auth_provider_configs.get(auth_provider_configs.ConfigName.JWT_PRIVATE_KEY.value)
    if not signing_key and not signing_key.strip(' '):
        raise JWTInvalidError(
            'The private key of JWT is not configured in the configuration of the admin site')

    return TokenBackend(
        algorithm='RS512', signing_key=signing_key, verifying_key=verifying_key
    )


class Token(BaseAAIToken):
    token_type = ''
    lifetime = timedelta(minutes=0)
    EXPIRATION_CLAIM = 'exp'
    TOKEN_TYPE_CLAIM = 'type'
    JTI_CLAIM = None  # 无效时，生成的token不包含此内容
    ISSUER_CLAIM = 'iss'

    def get_token_backend(self) -> TokenBackend:
        # Backward compatibility.
        return self.token_backend

    def __init__(self, token=None, verify=True, backend: TokenBackend = None):
        """
        :raises: JWTInvalidError
        """
        token_backend = backend if backend else build_token_backend()
        super().__init__(token=token, backend=token_backend, verify=verify)


class AccessToken(Token):
    token_type = 'accessToken'
    lifetime = timedelta(minutes=60)

    @classmethod
    def for_user(cls, user: InternalUser):
        """
        Returns an authorization token for the given user that will be provided
        after authenticating the user's credentials.
        """
        token = cls()
        token.set_header(key=cls.TOKEN_TYPE_CLAIM, value=cls.token_type)
        token.set_header(key='typ', value='JWT')
        token.set_iss(claim=cls.ISSUER_CLAIM, value=str(user.id))
        token['id'] = str(user.id)
        token['name'] = user.true_name
        token['email'] = user.email
        token['orgName'] = user.org_name
        token['country'] = None
        token['voJson'] = None
        token['sourceId'] = str(user.id)

        return token


class RefreshToken(Token):
    token_type = "refreshToken"
    lifetime = timedelta(hours=24)
    JTI_CLAIM = None    # 'jti'

    @classmethod
    def for_user(cls, user: InternalUser):
        token = cls()
        token.set_header(key=cls.TOKEN_TYPE_CLAIM, value=cls.token_type)
        token.set_header(key='typ', value='JWT')
        token.set_iss(claim=cls.ISSUER_CLAIM, value=str(user.id))
        token['id'] = str(user.id)
        token['refreshToken'] = ''    # 无用，为了兼容旧接口jwt格式
        return token

    def internal_user_id(self):
        return self['id']

    def access_token(self, user: InternalUser) -> AccessToken:
        access = AccessToken.for_user(user)
        access.set_exp(from_time=self.current_time)
        return access


class UntypedToken(Token):
    token_type = "untyped"

    def verify_token_type(self):
        pass
